#include "GameEngine.h"
#include <stdio.h>
#include <map>
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include "Timer.h"
#include "HeartHolder.h"
#include <sstream>
#include <stdlib.h>

#define FPS				60

using namespace std;

#define KEYSNO 8

enum GAMEKEYS {
   KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_PUNCH, KEY_P, KEY_ENTER, KEY_ESCAPE
};

bool key[KEYSNO] = {false, false, false, false, false, false, false, false};

ALLEGRO_BITMAP *currlevel;
//Maybe levels should hold their sprites
Popeye *popeye_s;
Olive *olive_s;
Brutus *brutus_s;
StartButton *startButton_s, *pauseButton_s,
			*winButton_s, *gameOverButton_s;
Spinach *spinach_s;
TrophyDisplay *trophyDisplay;
PopeyeFace *popeyeFace_s;

GameEngine::GameEngine() {
	Timer::setgametime();
	CollisionChecker::Initialize();
	InitiallizeAllegro();
	InitiallizeGraphics();
	GameState::GameStateInit();
	HeartHolder::Initialize();
	Scores::Initialize();
	AudioHolder::Initialize();
	AudioHolder::ChangeToSound("intro");
}

GameEngine::~GameEngine() {};

void GameEngine::InitiallizeAllegro(void) {
	//initialize allegro routines
	if(!al_init()) {
		fprintf(stderr, "failed to initialize allegro!\n");
		exit(1);
	}

	timer = al_create_timer(1.0 / FPS);
	if(!timer) {
		fprintf(stderr, "failed to create timer!\n");
		exit(1);
	}

	display = al_create_display(SCREEN_WIDTH, SCREEN_HEIGHT);
	if(!display) {
		fprintf(stderr, "failed to create display!\n");
		al_destroy_timer(timer);
		exit(1);
	}
	
	if(!al_init_image_addon()) {
      al_show_native_message_box(display, "Error", "Error", "Failed to initialize al_init_image_addon!", NULL, ALLEGRO_MESSAGEBOX_ERROR);
      al_destroy_display(display);
	  al_destroy_timer(timer);
	  exit(1);
	}

	if(!al_install_mouse()) {
		al_show_native_message_box(display, "Error", "Error", "failed to initialize the mouse!\n", NULL, ALLEGRO_MESSAGEBOX_ERROR);
		al_destroy_display(display);
		al_destroy_timer(timer);
		exit(1);
	}

	if(!al_install_keyboard()) {
		al_show_native_message_box(display, "Error", "Error", "failed to initialize the keyboard!\n", NULL, ALLEGRO_MESSAGEBOX_ERROR);
		al_destroy_display(display);
		al_destroy_timer(timer);
		exit(1);	
	}
 
	if(!al_install_audio()) {
		al_show_native_message_box(display, "Error", "Error", "failed to initialize audio!\n", NULL, ALLEGRO_MESSAGEBOX_ERROR);
		al_destroy_display(display);
		al_destroy_timer(timer);
		exit(1);
	}
 
	if(!al_init_acodec_addon()) {
		al_show_native_message_box(display, "Error", "Error", "failed to initialize audio codecs!\n", NULL, ALLEGRO_MESSAGEBOX_ERROR);
		al_destroy_display(display);
		al_destroy_timer(timer);
		exit(1);
	}
 
	if (!al_reserve_samples(1)) {
		al_show_native_message_box(display, "Error", "Error", "failed to reserve samples!\n", NULL, ALLEGRO_MESSAGEBOX_ERROR);
		al_destroy_display(display);
		al_destroy_timer(timer);
		exit(1);
	}

	event_queue = al_create_event_queue();
	if(!event_queue) {
		al_show_native_message_box(display, "Error", "Error", "failed to create event_queue!\n", NULL, ALLEGRO_MESSAGEBOX_ERROR);
		al_destroy_display(display);
		al_destroy_timer(timer);
		exit(0);
	}
	al_register_event_source(event_queue, al_get_display_event_source(display));
	al_register_event_source(event_queue, al_get_timer_event_source(timer));
	al_register_event_source(event_queue, al_get_keyboard_event_source());
	al_register_event_source(event_queue, al_get_mouse_event_source());

	al_init_font_addon();
	al_init_ttf_addon();
	
	font24 = al_load_font("fonts/PrStart.ttf", 16, 0);

	return;
}

void GameEngine::InitiallizeGraphics(void) {
	
	LevelTerrainHolder::Initialize("config/levels.ini");
	AnimationFilmHolder::Initialize("config/films.ini");
	AnimationFilmHolder *animFH = AnimationFilmHolder::GetSingleton();
	//add start game button
	FlashingAnimation *flashAnimation = new FlashingAnimation(1, 250, 600, 0);
	FlashingAnimator *flashAnimator = new FlashingAnimator();
	startButton_s = new StartButton(0, 0, (AnimationFilm *)AnimationFilmHolder::GetSingleton()->GetFilm("StartButton"), 
									flashAnimation, flashAnimator);
	AnimatorHolder::Register(flashAnimator);
	//add pause button
	flashAnimation = new FlashingAnimation(1, 250, 600, 0);
	flashAnimator = new FlashingAnimator();
	pauseButton_s = new StartButton(0, 0, (AnimationFilm *)AnimationFilmHolder::GetSingleton()->GetFilm("PauseButton"), 
									flashAnimation, flashAnimator);
	AnimatorHolder::Register(flashAnimator);
	//add win button
		//add pause button
	flashAnimation = new FlashingAnimation(1, 250, 600, 0);
	flashAnimator = new FlashingAnimator();
	winButton_s = new StartButton(0, 0, (AnimationFilm *)AnimationFilmHolder::GetSingleton()->GetFilm("WinButton"), 
									flashAnimation, flashAnimator);
	AnimatorHolder::Register(flashAnimator);
	//add gameover button
	flashAnimation = new FlashingAnimation(1, 250, 600, 0);
	flashAnimator = new FlashingAnimator();
	gameOverButton_s = new StartButton(0, 0, (AnimationFilm *)AnimationFilmHolder::GetSingleton()->GetFilm("GameOverButton"), 
									flashAnimation, flashAnimator);
	AnimatorHolder::Register(flashAnimator);
	//add popeye
	int total_frames =  AnimationFilmHolder::GetSingleton()->GetFilm("popeye_walk")->GetTotalFrames();
	FrameRangeAnimation *walkAnimation = new FrameRangeAnimation(0, total_frames-1,
																 0, 0, 100, true, POPEYE_ANIM);
	FrameRangeAnimator *walkAnimator = new FrameRangeAnimator();
	AnimatorHolder::Register(walkAnimator);

	total_frames =  AnimationFilmHolder::GetSingleton()->GetFilm("popeye_punch")->GetTotalFrames();
	FrameRangeAnimation *punchAnimation = new FrameRangeAnimation(0, total_frames-1,
																 0, 0, 200, false, POPEYE_ANIM+1);
	FrameRangeAnimator *punchAnimator = new FrameRangeAnimator();
	AnimatorHolder::Register(punchAnimator);

	MovingAnimation *fallAnimation = new MovingAnimation(0, 0, 50, false, POPEYE_ANIM+2);
	MovingAnimator *fallAnimator = new MovingAnimator();

	MovingAnimation *deathAnimation = new MovingAnimation(0, 0, 100, false, POPEYE_ANIM+3);
	MovingAnimator *deathAnimator = new MovingAnimator();
	AnimatorHolder::Register(fallAnimator);

	popeye_s = new Popeye(POPEYE_START_X, POPEYE_START_Y, 
						(AnimationFilm*)AnimationFilmHolder::GetSingleton()->GetFilm("popeye_walk"),
						 walkAnimation, walkAnimator, punchAnimation, punchAnimator,
						 fallAnimation, fallAnimator, deathAnimation, deathAnimator);
	//olive sprites
	popeye_s->SetVisibility(false);

	total_frames =  AnimationFilmHolder::GetSingleton()->GetFilm("olive_walk")->GetTotalFrames();
	FrameRangeAnimation *oliveWalkAnimation = new FrameRangeAnimation(0, total_frames-1,
																 0, 0, 200, false, OLIVE_ANIM);

	FrameRangeAnimator *oliveWalkAnimator = new FrameRangeAnimator();
	AnimatorHolder::Register(oliveWalkAnimator);

	total_frames =  AnimationFilmHolder::GetSingleton()->GetFilm("olive_drop_heart")->GetTotalFrames();
	FrameRangeAnimation *oliveDropAnimation = new FrameRangeAnimation(0, total_frames-1,
																 0, 0, 500, false, OLIVE_ANIM+1);
	FrameRangeAnimator *oliveDropAnimator= new FrameRangeAnimator();
	AnimatorHolder::Register(oliveDropAnimator);
	
	olive_s = new Olive(OLIVE_START_X, OLIVE_START_Y, 
						(AnimationFilm*)AnimationFilmHolder::GetSingleton()->GetFilm("olive_walk"),
						 oliveWalkAnimation, oliveWalkAnimator, oliveDropAnimation, oliveDropAnimator);
	olive_s->SetVisibility(false);

	//add spinach
	spinach_s = new Spinach(0, 0, (AnimationFilm*)AnimationFilmHolder::GetSingleton()->GetFilm("spinach"));
	CollisionChecker::GetSingleton()->Register(spinach_s, popeye_s);

	//ADD Brutus
	total_frames =  AnimationFilmHolder::GetSingleton()->GetFilm("brutus_walk")->GetTotalFrames();
	walkAnimation = new FrameRangeAnimation(0, total_frames-1, 0, 0, 100, true, POPEYE_ANIM);
	walkAnimator = new FrameRangeAnimator();
	AnimatorHolder::Register(walkAnimator);

	total_frames =  AnimationFilmHolder::GetSingleton()->GetFilm("brutus_punch_up")->GetTotalFrames();
	FrameRangeAnimation *punchUpAnimation = new FrameRangeAnimation(1, total_frames-1,
																 0, 0, 200, false, POPEYE_ANIM+1);
	FrameRangeAnimator *punchUpAnimator = new FrameRangeAnimator();
	AnimatorHolder::Register(punchUpAnimator);

	total_frames =  AnimationFilmHolder::GetSingleton()->GetFilm("brutus_punch_down")->GetTotalFrames();
	FrameRangeAnimation *punchDownAnimation = new FrameRangeAnimation(1, total_frames-1,
																 0, 0, 200, false, POPEYE_ANIM+2);
	FrameRangeAnimator *punchDownAnimator = new FrameRangeAnimator();
	AnimatorHolder::Register(punchDownAnimator);

	fallAnimation = new MovingAnimation(0, 0, 50, false, POPEYE_ANIM+2);
	fallAnimator = new MovingAnimator();
	AnimatorHolder::Register(fallAnimator);

	brutus_s = new Brutus(BRUTUS_START_X, BRUTUS_START_Y, 
						(AnimationFilm*)AnimationFilmHolder::GetSingleton()->GetFilm("brutus_walk"),
						 walkAnimation, walkAnimator, punchUpAnimation, punchUpAnimator,
						 punchDownAnimation, punchDownAnimator, fallAnimation, fallAnimator);
	//popeye face sprite
	popeyeFace_s = new PopeyeFace(0, 0, (AnimationFilm*)AnimationFilmHolder::GetSingleton()->GetFilm("popeye_face"));


	CollisionChecker::GetSingleton()->Register(brutus_s, popeye_s);

	ai->Register(olive_s, (olive_s->GenerateNextMove), 400, 0);
	ai->Register(spinach_s, (spinach_s->GenerateNextMove), 5000, 0);
	ai->Register(brutus_s, (brutus_s->GenerateNextMove), 500, 0);
	//for brutus 
	ai->setPopeye(popeye_s);
	//probably add init sounds here
	return;
}

MovingPathAnimation *createUpAnimation(int x, int y, const std::string film_id) {
	std::list<PathEntry> paths;
	PathEntry path;
	Rect rect = AnimationFilmHolder::GetSingleton()->GetFilm(film_id)->GetFrameBox(0);
	paths.push_back(PathEntry(0,0,false,false,0,50));
	paths.push_back(PathEntry(0,-10,true,false,0,100));
	paths.push_back(PathEntry(0,-10,false,false,0,100));
	paths.push_back(PathEntry(0,-10,true,false,0,100));
	paths.push_back(PathEntry(0,-10,false,false,0,100));
	paths.push_back(PathEntry(0,-10,true,false,0,100));
	paths.push_back(PathEntry(0,-10,false,false,1,100));
	return new MovingPathAnimation(paths, 0);
}

MovingPathAnimation *createDownAnimation(int x, int y, const std::string film_id) {
	std::list<PathEntry> paths;
	PathEntry path;
	Rect rect = AnimationFilmHolder::GetSingleton()->GetFilm(film_id)->GetFrameBox(0);
	paths.push_back(PathEntry(0,0,false,false,0,50));
	paths.push_back(PathEntry(0,10,true,false,0,100));
	paths.push_back(PathEntry(0,10,false,false,0,100));
	paths.push_back(PathEntry(0,10,true,false,0,100));
	paths.push_back(PathEntry(0,10,false,false,0,100));
	paths.push_back(PathEntry(0,10,true,false,0,100));
	paths.push_back(PathEntry(0,10,false,false,1,100));
	return new MovingPathAnimation(paths, 0);
}

MovingPathAnimation *createDiagonalClimbUpAnimation(bool flip_h) {
	std::list<PathEntry> paths;
	int direction = 1;
	if(flip_h) direction = -1;
	paths.push_back(PathEntry(0,0,flip_h,false,0,50));
	paths.push_back(PathEntry(direction*4,-8,flip_h,false,1,100));
	paths.push_back(PathEntry(direction*4,-8,flip_h,false,0,100));
	return new MovingPathAnimation(paths, 0);
}

MovingPathAnimation *createDiagonalClimbDownAnimation(bool flip_h) {
	std::list<PathEntry> paths;
	int direction = 1;
	if(flip_h) direction = -1;
	paths.push_back(PathEntry(0,0,flip_h,false,0,50));
	paths.push_back(PathEntry(direction*4,8,flip_h,false,1,100));
	paths.push_back(PathEntry(direction*4,8,flip_h,false,0,100));
	return new MovingPathAnimation(paths, 0);
}

enum TerrainObjectType {
	Error = -1,
	Platforms = 0,
	VerticalStairs = 1,
	LeftStairs = 2,
	RightStairs =3,
	SpinachBoxes = 4,
	Characters = 5,
	Buttons = 6,
	TrophyDisplays = 7,
	OtherSprites = 8
};

void GameEngine::LoadLevel(const string &level) {
	LevelTerrain *lvl = const_cast<LevelTerrain*>((LevelTerrainHolder::GetSingleton())->GetTerrain(level));
	currlevel = bitmapLoader.Load(lvl->GetBitmapPath());

	//reset visible sprites
	startButton_s->SetVisibility(false);
	pauseButton_s->SetVisibility(false);
	winButton_s->SetVisibility(false);
	gameOverButton_s->SetVisibility(false);
	popeye_s->SetVisibility(false);
	olive_s->SetVisibility(false);
	spinach_s->SetVisibility(false);
	brutus_s->SetVisibility(false);
	popeyeFace_s->SetVisibility(false);

	//	PlatformHolder::addPlatform(new Platform(Rect(2*8,2*204,2*240,2*36)));
	char buff[512], type[50], id[50], ch = ' ', top[50], bottom[50];
    int x, y, w, h;
	int x1, y1, w1, h1, x2, y2, w2, h2, x3, y3, w3, h3, x4, y4, w4, h4;
	unsigned int max_rows, max_cols, x_offset, y_offset;
	bool left_open, right_open;
	map<string, Platform *> platforms;
	vector<Step *> steps;
	Stair *stair;
	SpinachBox *sbox;
	TerrainObjectType objectType;
	std::ifstream cfg(lvl->GetTerrainConfPath());
    while(!cfg.eof()) {
		ch = cfg.peek();
		//printf("char=%c", ch);
		if(ch == '[') {
			cfg.getline(buff, 512);
			sscanf(buff, "%s", type);
			string type_s = string(type);
			if(type_s.compare("[Platforms]") == 0) {
				objectType = Platforms;
			}
			else if(type_s.compare("[LeftStairs]") == 0)
				objectType = LeftStairs;
			else if(type_s.compare("[RightStairs]") == 0)
				objectType = RightStairs;
			else if(type_s.compare("[VerticalStairs]") == 0)
				objectType = VerticalStairs;
			else if(type_s.compare("[TrophyDisplays]") == 0)
				objectType = TrophyDisplays;
			else if(type_s.compare("[SpinachBoxes]") == 0)
				objectType = SpinachBoxes;
			else if(type_s.compare("[Characters]") == 0)
				objectType = Characters;
			else if(type_s.compare("[Buttons]") == 0)
				objectType = Buttons;
			else if(type_s.compare("[OtherSprites]") == 0)
				objectType = OtherSprites;
			else
				objectType = Error;
		}
        else if(ch != '#' && ch != '\n') {
			cfg.getline(buff, 512);
			//printf("x=%d y=%d w=%d h=%d\n", x, y, w, h);
			switch(objectType) {
			
			case Platforms:
				sscanf(buff, "id=%s x=%d y=%d w=%d h=%d left_edge=%s right_edge=%s", id, &x, &y, &w, &h, top, bottom);
				//printf(buff, "id=%s x=%d y=%d w=%d h=%d\n\n", id, x, y, w, h);
				left_open = (string(top).compare("open") == 0);
				right_open = (string(bottom).compare("open") == 0);
				platforms[id] = new Platform(Rect(SCALE*x, SCALE*y, SCALE*w, SCALE*h), left_open, right_open);
				PlatformHolder::addPlatform(platforms[id]);
				break;
			case LeftStairs:
				sscanf(buff, 
					"top_platform=%s bottom_platform=%s x1=%d y1=%d w1=%d h1=%d, x2=%d y2=%d w2=%d h2=%d, x3=%d y3=%d w3=%d h3=%d, x4=%d y4=%d w4=%d h4=%d",
					top, bottom, &x1, &y1, &w1, &h1, &x2, &y2, &w2, &h2, &x3, &y3, &w3, &h3, &x4, &y4, &w4, &h4);
				steps.push_back(new Step(SCALE*x1, SCALE*y1, SCALE*w1, SCALE*h1));
				steps.push_back(new Step(SCALE*x2, SCALE*y2, SCALE*w2, SCALE*h2));
				steps.push_back(new Step(SCALE*x3, SCALE*y3, SCALE*w3, SCALE*h3));
				steps.push_back(new Step(SCALE*x4, SCALE*y4, SCALE*w4, SCALE*h4));
				stair = new LeftStair(platforms[top], platforms[bottom], steps,
					createDiagonalClimbUpAnimation(true), 
					createDiagonalClimbDownAnimation(false), 
					new MovingPathAnimator());
				platforms[top]->addGoingDownStair(stair);
				platforms[bottom]->addGoingUpStair(stair);
				steps.clear();
				break;
			case RightStairs:
				sscanf(buff, 
					"top_platform=%s bottom_platform=%s x1=%d y1=%d w1=%d h1=%d, x2=%d y2=%d w2=%d h2=%d, x3=%d y3=%d w3=%d h3=%d, x4=%d y4=%d w4=%d h4=%d",
					top, bottom, &x1, &y1, &w1, &h1, &x2, &y2, &w2, &h2, &x3, &y3, &w3, &h3, &x4, &y4, &w4, &h4);
				steps.push_back(new Step(SCALE*x1, SCALE*y1, SCALE*w1, SCALE*h1));
				steps.push_back(new Step(SCALE*x2, SCALE*y2, SCALE*w2, SCALE*h2));
				steps.push_back(new Step(SCALE*x3, SCALE*y3, SCALE*w3, SCALE*h3));
				steps.push_back(new Step(SCALE*x4, SCALE*y4, SCALE*w4, SCALE*h4));
				stair = new RightStair(platforms[top], platforms[bottom], steps,
					createDiagonalClimbUpAnimation(false), 
					createDiagonalClimbDownAnimation(true), 
					new MovingPathAnimator());
				platforms[top]->addGoingDownStair(stair);
				platforms[bottom]->addGoingUpStair(stair);
				steps.clear();
				break;
			case VerticalStairs:
				sscanf(buff, "top_platform=%s botton_platform=%s x=%d y=%d w=%d h=%d", top, bottom, &x, &y, &w, &h);
				steps.push_back(new Step(SCALE*x, SCALE*y, SCALE*w, SCALE*h));
				stair = new VerticalStair(platforms[top], platforms[bottom], steps, 
					createUpAnimation(SCALE*x, SCALE*y, "popeye_climb_vertical"), 
					createDownAnimation(SCALE*x, SCALE*y, "popeye_climb_vertical"), 
					new MovingPathAnimator());
				platforms[top]->addGoingDownStair(stair);
				platforms[bottom]->addGoingUpStair(stair);
				steps.clear();
				break;
			case TrophyDisplays:
				sscanf(buff, "type=%s firts_slot=(x=%d y=%d w=%d h=%d) max_rows=%d max_cols=%d x_offset=%d y_offset=%d",
					id, &x, &y, &w, &h, &max_rows, &max_cols, &x_offset, &y_offset);
				if(string(id).compare("HeartTrophyDisplay") == 0) {
					trophyDisplay = new HeartTrophyDisplay(Rect(SCALE*x, SCALE*y, SCALE*w, SCALE*h), max_cols, max_rows,
															SCALE*x_offset, SCALE*y_offset);
					HeartHolder::SetTrophyDisplay(trophyDisplay);
				}
				break;
			case Characters:
				sscanf(buff, "id=%s start_x=%d start_y=%d platform=%s", id, &x, &y, bottom);
				if(string(id).compare("Popeye") == 0) {
					popeye_s->SetPlatform(platforms[bottom]);
					popeye_s->SetX(x);
					popeye_s->SetY(y);
					popeye_s->SetVisibility(true);
					platforms[bottom]->AlignWithPlatform(popeye_s);
				}
				else if(string(id).compare("Olive") == 0) {
					olive_s->SetPlatform(platforms[bottom]);
					olive_s->SetX(x);
					olive_s->SetY(y);
					olive_s->SetVisibility(true);
					platforms[bottom]->AlignWithPlatform(olive_s);
				}
				else if(string(id).compare("Brutus") == 0) {
					brutus_s->SetPlatform(platforms[bottom]);
					brutus_s->SetX(x);
					brutus_s->SetY(y);
					brutus_s->SetVisibility(true);
					platforms[bottom]->AlignWithPlatform(brutus_s);	
				}
				break;
			case SpinachBoxes:
				sscanf(buff, "platform=%s x=%d y=%d w=%d h=%d", bottom, &x, &y, &w, &h);
				sbox = new SpinachBox(Rect(SCALE*x, SCALE*y, SCALE*w, SCALE*h));
				platforms[bottom]->addSpinachBox(sbox);
				spinach_s->AddSpinachBox(sbox);
				break;
			case Buttons:
				sscanf(buff, "id=%s start_x=%d start_y=%d", id, &x, &y);
				if(string(id).compare("StartButton") == 0) {
					startButton_s->SetX(x);
					startButton_s->SetY(y);
					startButton_s->SetVisibility(true);
				}
				else if(string(id).compare("PauseButton") == 0) {
					pauseButton_s->SetX(x);
					pauseButton_s->SetY(y);
					//pauseButton_s->SetVisibility(true);
				}
				else if(string(id).compare("WinButton") == 0) {
					winButton_s->SetX(x);
					winButton_s->SetY(y);
				}
				else if(string(id).compare("GameOverButton") == 0) {
					gameOverButton_s->SetX(x);
					gameOverButton_s->SetY(y);
				}
				break;
			case OtherSprites:
				sscanf(buff, "id=%s start_x=%d start_y=%d", id, &x, &y);
				popeyeFace_s->SetX(SCALE*x);
				popeyeFace_s->SetY(SCALE*y);
				popeyeFace_s->SetVisibility(true);
				break;
			default:
				break;
				//al_show_native_message_box(display, "Error", "Error", ("Could not load level "+level).c_str(), NULL, ALLEGRO_MESSAGEBOX_ERROR);
				//exit(1);
			}
		}
		else {
			cfg.ignore(512, '\n');
		}
		ch = cfg.peek();
		if(ch == ' ') break;
    }
    cfg.close();
}

void displayLevel() {
	al_draw_scaled_rotated_bitmap(currlevel, 0, 0, 0, 0, 2, 2, 0, 0);
}

bool GameEngine::hasWon(void) {
	if(trophyDisplay->isFull()) {
		AudioHolder::ChangeToSound("clear");
		GameState::PlayerWin();
		return true;
	}
	return  false;
}

bool GameEngine::hasLost(void) {
	if(popeye_s->isDead() ||
		HeartHolder::isHeartBroken()) 
	{
		GameState::GameOver();
		return true;
	}
	return false;
}

void  GameEngine::Input(void) {
	
	if(key[KEY_ESCAPE]) {
		GameState::makeKilled();
	}
	
	if(GameState::isTitle()) {
		if(key[KEY_ENTER]) {
			startButton_s->StopFlashing();
			LoadLevel("level01");
			GameState::makeRunning();
			spinach_s->PlaceOnNextSpinachBox();
			ai->StartAI();
			AudioHolder::ChangeToSound("level01");
		}
	}

	if(!GameState::isRunning()) 
		return;
	else {
		if(hasWon()) {
			AnimatorHolder::Pause();
			winButton_s->StartFlashing();
			winButton_s->SetVisibility(true);
			return;
		}
		else if(hasLost()) {
			AnimatorHolder::Pause();
			popeye_s->PlayDeathAnimation();
			gameOverButton_s->StartFlashing();
			gameOverButton_s->SetVisibility(true);
			return;
		}
		
		if(key[KEY_UP]) {
			popeye_s->MoveUp();
		}
		else if(key[KEY_DOWN]) {
			popeye_s->MoveDown();
		}
		else if(key[KEY_LEFT]) {
			popeye_s->MoveHorizontal(-10);
		}
		else if(key[KEY_RIGHT]) {
			popeye_s->MoveHorizontal(10);
		}
		else if(key[KEY_PUNCH]) {
			popeye_s->Punch();
		}
		else {
			popeye_s->StopMoving();
		}
	}
}

void GameEngine::PauseGame(void) {
	if(GameState::isPaused()) {
		GameState::makeRunning();
		AnimatorHolder::Resume();
		pauseButton_s->StopFlashing();
		pauseButton_s->SetVisibility(false);
	}
	else if(GameState::isRunning()) {
		GameState::makePaused();
		AnimatorHolder::Pause();
		pauseButton_s->StartFlashing();
		pauseButton_s->SetVisibility(true);
	}
}

void GameEngine::GameLoop(void) {
	al_start_timer(timer);
	LoadLevel("MainMenu");
	startButton_s->StartFlashing();

	while(!GameState::isKilled()) {
		Timer::setgametime();
		ALLEGRO_EVENT ev;
		al_wait_for_event(event_queue, &ev);
		if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
			break;
		}
		else if(ev.type == ALLEGRO_EVENT_KEY_DOWN) {
			switch(ev.keyboard.keycode) {
				case ALLEGRO_KEY_UP:
					key[KEY_UP] = true;
					break;
				case ALLEGRO_KEY_DOWN:
					key[KEY_DOWN] = true;
					break;
				case ALLEGRO_KEY_LEFT:
					key[KEY_LEFT] = true;
					break;
				case ALLEGRO_KEY_RIGHT:
					key[KEY_RIGHT] = true;
					break;
				case ALLEGRO_KEY_A:
					key[KEY_PUNCH] = true;
					break;
				case ALLEGRO_KEY_P:
					PauseGame();
					break;
				case ALLEGRO_KEY_ENTER:
					key[KEY_ENTER] = true;
					break;
				case ALLEGRO_KEY_ESCAPE:
					key[KEY_ESCAPE] = true;
					break;
			}
		}
		else if(ev.type == ALLEGRO_EVENT_KEY_UP) {
			switch(ev.keyboard.keycode) {
				case ALLEGRO_KEY_UP:
					key[KEY_UP] = false;
					break;
				case ALLEGRO_KEY_DOWN:
					key[KEY_DOWN] = false;
					break;
				case ALLEGRO_KEY_LEFT: 
					key[KEY_LEFT] = false;
					break;
				case ALLEGRO_KEY_RIGHT:
					key[KEY_RIGHT] = false;
					break;
				case ALLEGRO_KEY_A:
					key[KEY_PUNCH] = false;
					break;
				case ALLEGRO_KEY_ENTER:
					key[KEY_ENTER] = false;
					break;
				case ALLEGRO_KEY_ESCAPE:
					key[KEY_ESCAPE] = false;
					break;
			}
		}
		Input();
		if(GameState::isRunning()) {
			Scores::changeTopScore();
			popeyeFace_s->checkMode(popeye_s);
			ai->setPopeye(popeye_s);
			CollisionChecker::GetSingleton()->RegisterHearts(popeye_s);
			CollisionChecker::GetSingleton()->Check(); //to ekana singleton, dn eimai sigouros oti einai aparaithto
		}
		AnimatorHolder::Progress(Timer::getgametime());
		RenderDisplay();
		//Destroy-Cancel objects here
	}

	GameExit();
}

void GameEngine::GameExit(void) {
	AnimationFilmHolder::Delete();
	al_destroy_display(display);
	al_destroy_timer(timer);
	al_destroy_event_queue(event_queue);
}

void GameEngine::RenderDisplay(void) {
	displayLevel();
	if(startButton_s->IsVisible())
		startButton_s->Display(Rect(0,0,0,0));
	if(spinach_s->IsVisible())
		spinach_s->Display(Rect(0,0,0,0));
	if(olive_s->IsVisible())
		olive_s->Display(Rect(0,0,0,0));
	if(brutus_s->IsVisible())
		brutus_s->Display(Rect(0,0,0,0));
	if(popeye_s->IsVisible()) //popeye should be painted last, z-ordering
		popeye_s->Display(Rect(0,0,0,0));
	HeartHolder::DisplayAll();
	if(popeyeFace_s->IsVisible())
		popeyeFace_s->Display(Rect(0,0,0,0));
	if(pauseButton_s->IsVisible())
		pauseButton_s->Display(Rect(0,0,0,0));
	if(winButton_s->IsVisible())
		winButton_s->Display(Rect(0,0,0,0));
	if(gameOverButton_s->IsVisible())
		gameOverButton_s->Display(Rect(0,0,0,0));

	if(!GameState::isTitle()) {
		//score
		al_draw_text(font24, al_map_rgb(255, 255, 255), 35, 35, 0, Scores::ScoreToString());
		//popeye lifes
		std::stringstream strlives;
		strlives << popeye_s->getLives();

		al_draw_text(font24, al_map_rgb(255, 0, 0), 446, 108, 0, strlives.str().c_str());
		//lvl
		al_draw_text(font24, al_map_rgb(255, 0, 0), 446, 126, 0, "1");
	}
	al_flip_display();
	al_clear_to_color(al_map_rgb(0,0,0));
}